package com.shell.governor.authorization.service.impl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.shell.bee.base.exception.UnCheckException;
import com.shell.bee.base.utils.StringUtil;
import com.shell.bee.base.utils.SystemUtil;
import com.shell.bee.entity.auth.AuthRole;
import com.shell.bee.entity.auth.AuthUser;
import com.shell.bee.entity.mvc.RetMsg;
import com.shell.bee.persistence.annotation.Pagination;
import com.shell.bee.persistence.model.PageLimit;
import com.shell.bee.persistence.service.impl.PersistentServiceImpl;
import com.shell.constant.ind.PubConstants;
import com.shell.constant.rel.GovernorConstants;
import com.shell.framework.utils.CommonDataUtil;
import com.shell.framework.utils.SysDateUtil;
import com.shell.governor.authorization.dao.PubAuthorizationDao;
import com.shell.governor.authorization.dao.PubResourceDao;
import com.shell.governor.authorization.dao.PubRoleDao;
import com.shell.governor.authorization.dao.PubRoleResourceDao;
import com.shell.governor.authorization.po.PubAuthorization;
import com.shell.governor.authorization.po.PubResource;
import com.shell.governor.authorization.po.PubRole;
import com.shell.governor.authorization.service.PubRoleService;
import com.shell.governor.authorization.vo.AuthTmplRoleVo;
import com.shell.governor.modules.po.PubApplication;
import com.shell.governor.modules.po.PubDictionary;
import com.shell.governor.modules.service.PubApplicationService;

import tk.mybatis.mapper.entity.Example;

@Service
public class PubRoleServiceImpl extends PersistentServiceImpl<PubRole> implements PubRoleService {
	@Autowired
	PubRoleDao pubRoleDao;
	@Autowired
	PubRoleResourceDao pubRoleRResourceDao;
	@Autowired
	PubAuthorizationDao pubAuthorizationDao;
	@Autowired
	PubResourceDao pubResourceDao;
	@Autowired
	PubApplicationService pubApplicationService;

	public RetMsg saveOrUpdateRole(PubRole entity) {
		AuthUser user = CommonDataUtil.getCurUser();
		int retflag = 1;
		if (!checkCodeUnique(entity)) {
			return new RetMsg("error", "������������������");
		}
		String saveOrUpdateTip = "";
		if (StringUtil.trimEmpty(entity.getRoleId())) {
			entity.setRoleId(SystemUtil.getUUID());
			entity.setCreatorId(user.getUserId());
			entity.setRoleType("1");
			entity.setCreateTime(SysDateUtil.getSystemDateTime());
			entity.setRoleState("E");
			retflag = save(entity);
			PubAuthorization pubAuthorization = new PubAuthorization();
			List<AuthRole> list = CommonDataUtil.getCurUserRoles();
			boolean appAdmin = false;
			for (AuthRole role : list) {
				if ((role.getRoleType().equals("0")) && (entity.getAppId().equals(role.getAppId()))) {
					appAdmin = true;
					pubAuthorization.setRoleId(role.getRoleId());
					pubAuthorization.setAuzId(entity.getRoleId());
					pubAuthorization.setAuzType("0");
					retflag = this.pubAuthorizationDao.insert(pubAuthorization);
				}
			}
			if (!appAdmin) {
				for (AuthRole role : list) {
					if (role.getRoleCode().equals(GovernorConstants.DefaultRole.ADMIN_CODE)) {
						pubAuthorization.setRoleId(role.getRoleId());
						pubAuthorization.setAuzId(entity.getRoleId());
						pubAuthorization.setAuzType("0");
						retflag = this.pubAuthorizationDao.insert(pubAuthorization);
					}
				}
			}
			saveOrUpdateTip = "����������";
		} else {
			entity.setRoleName(entity.getRoleName());
			entity.setRoleCode(entity.getRoleCode());
			entity.setRoleState(entity.getRoleState());
			entity.setNote(entity.getNote());
			retflag = updateNotNull(entity);
			saveOrUpdateTip = "����������";
		}
		if (retflag == 1) {
			return new RetMsg("success", saveOrUpdateTip);
		}
		return new RetMsg("error", "����������������");
	}

	public boolean checkCodeUnique(PubRole entity) {
		if (StringUtils.isEmpty(entity.getRoleCode())) {
			return true;
		}
		Example example = new Example(PubRole.class);
		Example.Criteria criteria = example.createCriteria();
		if (StringUtil.trimEmpty(entity.getRoleId())) {
			entity.setRoleId("");
		}
		criteria.andNotEqualTo("roleId", entity.getRoleId());
		criteria.andEqualTo("roleCode", entity.getRoleCode());
		criteria.andNotEqualTo("roleState", "D");

		List<PubRole> list = selectByExample(example);
		if (list.size() > 0) {
			return false;
		}
		return true;
	}

	public RetMsg deleteRole(PubRole role) {
		int update_count = this.pubRoleDao.updateRoleStateWithCascade(role.getRoleId(), "D");
		PubAuthorization pubAuthorization = new PubAuthorization();
		pubAuthorization.setAuzId(role.getRoleId());
		int delete_count = this.pubAuthorizationDao.delete(pubAuthorization);
		if ((update_count > 0) && (delete_count > 0)) {
			return new RetMsg("success", "��������");
		}
		return new RetMsg("error", "����������");
	}

	@Pagination
	public List<PubRole> selectRolesByPage(PageLimit limit, PubRole role) {
		String userId = CommonDataUtil.getCurUser().getUserId();
		if (StringUtil.notEmpty(role.getRoleCode())) {
			String parameterLike = role.getRoleCode();
			parameterLike = parameterLike.replace("%", "").trim();
			parameterLike = "%" + parameterLike + "%";
			role.setRoleCode(parameterLike);
		}
		if (StringUtil.notEmpty(role.getRoleName())) {
			role.setRoleName(StringUtil.getParameterLike(role.getRoleName()));
		}
		role.setUserId(userId);

		return this.pubRoleDao.selectRoles(role);
	}

	public List<PubRole> selectRoleForUser(String userId, String entId) {
		Map<String, Object> m = new HashMap<String, Object>();
		m.put("userId", userId);
		m.put("terminalCode", PubConstants.TerminalCode.TRML_PC);
		return this.pubRoleDao.selectRoleForUser(m);
	}

	public List<PubRole> selectRoleByTerminalCode(String terminalCode) {
		PubRole role = new PubRole();
		role.setRoleState("E");
		return selectByEntity(role);
	}

	public List<PubRole> selectUserRole(String userId, String entId) {
		Map<String, Object> m = new HashMap<String, Object>();
		m.put("userId", userId);
		m.put("entId", entId);
		return this.pubRoleDao.selectUserRole(m);
	}

	public List<PubRole> selectRolesByCodes(String... roleCodes) {
		Example example = new Example(PubRole.class);
		Example.Criteria criteria = example.createCriteria();

		criteria.andEqualTo("roleState", "E");
		List<String> codes = Arrays.asList(roleCodes);
		criteria.andIn("roleCode", codes);
		example.setOrderByClause("role_name asc");
		List<PubRole> list = selectByExample(example);
		return list;
	}

	public int updateRoleStateWithCascade(String roleId, String roleState) {
		return this.pubRoleDao.updateRoleStateWithCascade(roleId, roleState);
	}

	public List<AuthTmplRoleVo> selectRole4AuthUser(String appId, String userId, String entId, String curUserId,
			String cusEntId) {
		return this.pubRoleDao.selectRole4AuthUser(appId, userId, entId, curUserId, cusEntId);
	}

	public List<PubRole> selectResourceRole(PubRole role) {
		String userId = CommonDataUtil.getUserId();
		PubAuthorization pubAuthorization = new PubAuthorization();
		pubAuthorization.setAuzId(role.getRoleId());
		pubAuthorization.setUserId(userId);
		pubAuthorization.setAppId(role.getAppId());
		return this.pubRoleDao.selectResourceRole(pubAuthorization);
	}

	public RetMsg authRoleToRole(String roleId, String roleIds) {
		if (!StringUtil.trimEmpty(roleId)) {
			PubAuthorization pa = new PubAuthorization();
			pa.setRoleId(roleId);
			this.pubAuthorizationDao.deleteByRoleId(pa);
			if (!StringUtil.trimEmpty(roleIds)) {
				String[] roleIdArr = roleIds.split(",");
				for (String rId : roleIdArr) {
					PubAuthorization pubAuthorization = new PubAuthorization();
					pubAuthorization.setRoleId(roleId);
					pubAuthorization.setAuzId(rId);
					pubAuthorization.setAuzType("1");
					this.pubAuthorizationDao.insert(pubAuthorization);
				}
			}
		} else {
			return new RetMsg("error", "����������");
		}
		return new RetMsg("success", "��������");
	}

	public List<PubResource> selectResourceTreeData4Role(String roleId, String type, String bizId)
			throws UnCheckException {
		PubRole role = (PubRole) this.pubRoleDao.selectByPrimaryKey(roleId);
		List<AuthRole> curUserRoles = CommonDataUtil.getCurUserRoles();
		for (AuthRole authRole : curUserRoles) {
			if (authRole.getRoleCode().equals(GovernorConstants.DefaultRole.ADMIN_CODE)) {
				roleId = null;
				break;
			}
			if ((authRole.getAppId().equals(role.getAppId())) && (authRole.getRoleType().equals("0"))) {
				roleId = authRole.getRoleId();
				break;
			}
		}
		if ((role.getRoleId().equals(roleId)) && (!role.getRoleType().equals("0"))) {
			return new ArrayList<PubResource>();
		}
		List<PubResource> ress = new ArrayList<PubResource>();
		try {
			List<PubApplication> apps = this.pubApplicationService.getApplication(null);
			Map<String, Object> nameValueMap = (Map) SystemUtil.getConstantsNameValueMap(PubConstants.class)
					.get("TerminalCode");
			Map<String, Object> valueMap = (Map) SystemUtil.getConstantsValueMap(PubConstants.class)
					.get("TerminalCode");
			for (PubApplication app : apps) {
				PubResource appRes = new PubResource();
				appRes.setResId(app.getAppCode());
				appRes.setResName(app.getAppAlias() + "(����)");
				List<PubResource> appRess = new ArrayList<PubResource>();
				for (String key : nameValueMap.keySet()) {
					if (!"current".equals(key)) {
						PubResource res = new PubResource();
						res.setResId((String) nameValueMap.get(key) + "_" + app.getAppId());
						res.setResName((String) valueMap.get(nameValueMap.get(key)) + "(����)");
						List<PubResource> resources = null;
						if (StringUtil.empty(bizId)) {
							resources = this.pubResourceDao.selectResouceTreeByApp(app.getAppId(), roleId,
									role.getRoleId(), type, (String) nameValueMap.get(key));
						} else {
							resources = this.pubResourceDao.selectResouceTreeBizByApp(app.getAppId(), bizId, roleId,
									role.getRoleId(), type, (String) nameValueMap.get(key));
						}
						List<PubResource> resTreeList = new ArrayList<PubResource>();
						if ((resources != null) && (resources.size() > 0)) {
							genSubResourceTree(resources, resTreeList, 0, 0);
							for (PubResource firstRes : resTreeList) {
								firstRes.setParentId(res.getResId());
								if (firstRes.isChecked()) {
									res.setChecked(true);
									appRes.setChecked(true);
								}
							}
							res.setChildren(resTreeList);
							res.setParentId(app.getAppCode());
							appRess.add(res);
						}
						res.setDisabled(true);
						appRes.setDisabled(true);
					}
				}
				if ((appRess != null) && (appRess.size() > 0)) {
					appRes.setChildren(appRess);
					ress.add(appRes);
				}
			}
		} catch (Exception e) {
			throw new UnCheckException(e.getMessage());
		}
		return ress;
	}

	private int genSubResourceTree(List<PubResource> resources, List<PubResource> children, int start, int level) {
		int index = start;
		while (index < resources.size()) {
			PubResource res = (PubResource) resources.get(index);
			if (res.getResLevel().intValue() == level) {
				children.add(res);
				res.setChildren(new ArrayList<PubResource>());
				index = genSubResourceTree(resources, res.getChildren(), index + 1, level + 1);
			} else {
				if (res.getResLevel().intValue() < level) {
					break;
				}
				if (res.getResLevel().intValue() > level) {
					index = genSubResourceTree(resources, children, index, res.getResLevel().intValue());
				}
			}
		}
		if (children.size() > 0) {
			Collections.sort(children, new Comparator<PubResource>() {
				@Override
				public int compare(PubResource arg0, PubResource arg1) {
					if ((arg0.getResSort() == null) && (arg1.getResSort() == null)) {
						return 0;
					}
					if (arg0.getResSort() == null) {
						return 1;
					}
					if (arg1.getResSort() == null) {
						return -1;
					}
					return arg0.getResSort().compareTo(arg1.getResSort());
				}
			});
		}
		return index;
	}

	public List<PubApplication> selectAppByAdminRole(String userId) {
		if (StringUtil.emptyAndNull(userId)) {
			return null;
		}
		return this.pubRoleDao.selectAppByAdminRole(userId);
	}

	public List<PubRole> getRoleByDict(PubDictionary dict) {
		List<PubRole> roleList = new ArrayList<PubRole>();
		String roleStr = dict.getExtension2();
		if (StringUtil.notTrimEmpty(roleStr)) {
			String[] roles = roleStr.split(",");
			for (String code : roles) {
				PubRole role = new PubRole();
				role.setRoleCode(code);
				role.setRoleState("E");
				role = (PubRole) selectOne(role);
				roleList.add(role);
			}
		}
		return roleList;
	}

	public PubRole getRoleInfoByRoleId(String roleId) {
		return this.pubRoleDao.getRoleInfoByRoleId(roleId);
	}
}
